package it.unibo.refolding.common;

import it.unibo.refolding.pico.PicoShapes;
import it.unibo.refolding.pico.RedundantPicoCurveInfo;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;

import javax.imageio.ImageIO;

import org.apache.batik.dom.GenericDOMImplementation;
import org.apache.batik.svggen.SVGGraphics2D;
import org.w3c.dom.DOMImplementation;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

import com.google.common.base.Charsets;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;

public class Images {

	private static SVGGraphics2D createSvgGraphics2D() {
		// Get a DOMImplementation.
		DOMImplementation domImpl = GenericDOMImplementation.getDOMImplementation();

		// Create an instance of org.w3c.dom.Document.
		String svgNS = "http://www.w3.org/2000/svg";
		Document document = domImpl.createDocument(svgNS, "svg", null);

		// Create an instance of the SVG Generator.
		SVGGraphics2D svgGenerator = new SVGGraphics2D(document);
		return svgGenerator;
	}

	private static void saveToFile(Element root, SVGGraphics2D graphics2D, Path svgPath) {
		try (Writer out = new OutputStreamWriter(Files.newOutputStream(svgPath), Charsets.ISO_8859_1)) {
			graphics2D.stream(root, out, true, false);
		} catch (IOException e) {
			throw new MyRuntimeException(e.getMessage(), e);
		}
	}

	public static void saveSvg(RedundantPicoCurveInfo picoAnalysis, double svgDefScale, Path svgPath) {
		Map<Color, List<Shape>> shapes = PicoShapes.draw(picoAnalysis, svgDefScale);
		saveSvg(shapes, svgPath);
	}

	public static void saveSvg(List<Shape> shapes, Path svgPath) {
		saveSvg(ImmutableMap.of(Color.BLACK, shapes), svgPath);
	}

	public static void saveSvg(Map<Color, List<Shape>> color2shapes, Path svgFile) {
		SVGGraphics2D svgGenerator = createSvgGraphics2D();
		Rectangle2D bounds = CommonThings.boundsOfUnion(ImmutableList.copyOf(Iterables
				.concat(color2shapes.values())));
		Dimension dimension = new Dimension((int) bounds.getWidth(), (int) bounds.getHeight());
		svgGenerator.setSVGCanvasSize(dimension);
		AffineTransform tx = new AffineTransform();
		tx.translate(-bounds.getMinX(), -bounds.getMinY());
		// tx.translate(0, bounds.getMinY());
		// tx.scale(1, -1);
		svgGenerator.transform(tx);
		for (Entry<Color, List<Shape>> entry : color2shapes.entrySet()) {
			svgGenerator.setColor(entry.getKey());
			for (Shape shape : entry.getValue()) {
				svgGenerator.draw(shape);
			}
		}
		Element root = svgGenerator.getRoot();
		String viewBoxString = String.format(Locale.ROOT, "%s %s %s %s", 0, 0, bounds.getWidth(),
				bounds.getHeight());
		root.setAttributeNS(null, "viewBox", viewBoxString);
		saveToFile(root, svgGenerator, svgFile);
	}

	public static void savePng(Map<Color, List<Shape>> shapes, String pngFilename) {
		Rectangle2D bounds = CommonThings.boundsOfUnion(Iterables.concat(shapes.values()));
		BufferedImage image = new BufferedImage(1024, 1024, BufferedImage.TYPE_BYTE_BINARY);
		Graphics2D g2d = image.createGraphics();
		// g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
		// RenderingHints.VALUE_ANTIALIAS_ON);
		AffineTransform tx = new AffineTransform();
		tx.scale(image.getWidth() / bounds.getWidth(), image.getHeight() / bounds.getHeight());
		tx.translate(-bounds.getMinX(), -bounds.getMinY());
		// tx.translate(0, bounds.getMinY());
		// tx.scale(1, -1);
		g2d.transform(tx);
		Color c = g2d.getColor();
		for (Map.Entry<Color, List<Shape>> e : shapes.entrySet()) {
			g2d.setColor(e.getKey());
			for (Shape shape : e.getValue()) {
				g2d.draw(shape);
			}
		}
		g2d.setColor(c);
		try {
			ImageIO.write(image, "png", new File(pngFilename));
		} catch (IOException e) {
			throw new MyRuntimeException(e.getMessage(), e);
		}
	}
}
